MCP Backup Server
by hexitex
Verified
- MCP-Backup-Server
- test scripts
import fs from 'fs';
import path from 'path';
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
// Get current directory
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Create a test file
const testDir = path.join(__dirname, 'test_files');
const testFile = path.join(testDir, 'test_file.txt');
// Create a test folder structure
const testFolderStructure = path.join(testDir, 'test_folder_structure');
const testSubFolder1 = path.join(testFolderStructure, 'subfolder1');
const testSubFolder2 = path.join(testFolderStructure, 'subfolder2');
const testFileInFolder1 = path.join(testSubFolder1, 'file1.txt');
const testFileInFolder2 = path.join(testSubFolder2, 'file2.txt');
// Ensure test directory exists
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir, { recursive: true });
}
// Create or update test file with content
fs.writeFileSync(testFile, `This is a test file created at ${new Date().toISOString()}`);
console.log(`Created test file at: ${testFile}`);
// Create test folder structure
if (!fs.existsSync(testFolderStructure)) {
fs.mkdirSync(testFolderStructure, { recursive: true });
}
if (!fs.existsSync(testSubFolder1)) {
fs.mkdirSync(testSubFolder1, { recursive: true });
}
if (!fs.existsSync(testSubFolder2)) {
fs.mkdirSync(testSubFolder2, { recursive: true });
}
// Create test files in subfolders
fs.writeFileSync(testFileInFolder1, `This is a test file in subfolder1 created at ${new Date().toISOString()}`);
fs.writeFileSync(testFileInFolder2, `This is a test file in subfolder2 created at ${new Date().toISOString()}`);
console.log(`Created test folder structure at: ${testFolderStructure}`);
// Start the server in a separate process
const server = spawn('node', ['dist/index.js'], {
stdio: ['pipe', 'pipe', 'inherit'],
env: {
...process.env,
BACKUP_DIR: path.join(__dirname, 'test_backups'),
MAX_VERSIONS: '3'
}
});
// Function to send a JSON-RPC request and get the response
function sendRequest(request) {
return new Promise((resolve, reject) => {
console.log(`Sending request: ${JSON.stringify(request)}`);
// Set up response handler
const responseHandler = (data) => {
const lines = data.toString().split('\n');
for (const line of lines) {
if (!line.trim()) continue;
try {
const response = JSON.parse(line);
// If this is a response to our request
if (response.id === request.id) {
server.stdout.removeListener('data', responseHandler);
resolve(response);
return;
}
} catch (error) {
console.error(`Error parsing response: ${line}`);
}
}
};
server.stdout.on('data', responseHandler);
// Send the request
server.stdin.write(JSON.stringify(request) + '\n');
// Set a timeout
setTimeout(() => {
server.stdout.removeListener('data', responseHandler);
reject(new Error('Request timed out'));
}, 10000);
});
}
// Run tests
async function runTests() {
try {
// Wait for server to start
await new Promise(resolve => setTimeout(resolve, 1000));
// Test 1: List available tools
console.log('\n=== Test 1: List Tools ===');
const toolsResponse = await sendRequest({
jsonrpc: '2.0',
method: 'tools/list',
params: {},
id: Date.now().toString()
});
console.log('Available tools:', JSON.stringify(toolsResponse.result, null, 2));
// Test 2: Create backup with agent context
console.log('\n=== Test 2: Create Backup with Agent Context ===');
const createResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_create',
arguments: {
file_path: testFile,
agent_context: "This is a sample agent context for file backup. It could contain the last part of a conversation or other metadata."
}
},
id: Date.now().toString()
});
console.log('Backup created:', JSON.stringify(createResult.result, null, 2));
// Test 3: List backups
console.log('\n=== Test 3: List Backups ===');
const listResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_list',
arguments: { file_path: testFile }
},
id: Date.now().toString()
});
console.log('Backups list:', JSON.stringify(listResult.result, null, 2));
// Test 4: Create another backup with different agent context
console.log('\n=== Test 4: Create Another Backup with Different Agent Context ===');
const createResult2 = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_create',
arguments: {
file_path: testFile,
agent_context: "This is a different agent context for the second backup. We can see how multiple backups store different context information."
}
},
id: Date.now().toString()
});
console.log('Second backup created:', JSON.stringify(createResult2.result, null, 2));
// Test 5: List backups again
console.log('\n=== Test 5: List Backups Again ===');
const listResult2 = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_list',
arguments: { file_path: testFile }
},
id: Date.now().toString()
});
console.log('Updated backups list:', JSON.stringify(listResult2.result, null, 2));
// Parse the content field from the response
let backups = [];
if (listResult2.result && listResult2.result.content && listResult2.result.content.length > 0) {
try {
backups = JSON.parse(listResult2.result.content[0].text);
} catch (err) {
console.error('Error parsing backups list:', err);
}
}
// Test 6: Restore the first backup
if (backups && backups.length > 0) {
console.log('\n=== Test 6: Restore Backup ===');
const timestamp = backups[0].timestamp;
const restoreResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_restore',
arguments: {
file_path: testFile,
timestamp: timestamp
}
},
id: Date.now().toString()
});
console.log('Restore result:', JSON.stringify(restoreResult.result, null, 2));
} else {
console.log('No backups found to restore');
}
// Test 7: Get Tool Documentation
console.log('\n=== Test 7: Get Tool Documentation ===');
const describeRequest = {
jsonrpc: '2.0',
method: 'tools/describe',
params: {
name: 'backup_create'
},
id: Date.now().toString()
};
console.log(`Sending request: ${JSON.stringify(describeRequest)}`);
await sendRequest(describeRequest).then(response => {
console.log(`Tool documentation: ${JSON.stringify(response, null, 2)}`);
});
// Test 8: Create folder backup with agent context
console.log('\n=== Test 8: Create Folder Backup with Agent Context ===');
const folderCreateResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_create',
arguments: {
folder_path: testFolderStructure,
include_pattern: "*.txt",
agent_context: "This is a sample agent context for folder backup. It demonstrates storing context with folder backups."
}
},
id: Date.now().toString()
});
console.log('Folder backup created:', JSON.stringify(folderCreateResult.result, null, 2));
// Test 9: List folder backups
console.log('\n=== Test 9: List Folder Backups ===');
const folderListResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_list',
arguments: { folder_path: testFolderStructure }
},
id: Date.now().toString()
});
console.log('Folder backups list:', JSON.stringify(folderListResult.result, null, 2));
// Test 10: Create another folder backup
console.log('\n=== Test 10: Create Another Folder Backup ===');
const folderCreateResult2 = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_create',
arguments: { folder_path: testFolderStructure }
},
id: Date.now().toString()
});
console.log('Second folder backup created:', JSON.stringify(folderCreateResult2.result, null, 2));
// Test 11: List folder backups again
console.log('\n=== Test 11: List Folder Backups Again ===');
const folderListResult2 = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_list',
arguments: { folder_path: testFolderStructure }
},
id: Date.now().toString()
});
console.log('Updated folder backups list:', JSON.stringify(folderListResult2.result, null, 2));
// Parse the content field from the response
let folderBackups = [];
if (folderListResult2.result && folderListResult2.result.content && folderListResult2.result.content.length > 0) {
try {
folderBackups = JSON.parse(folderListResult2.result.content[0].text);
} catch (err) {
console.error('Error parsing folder backups list:', err);
}
}
// Test 12: Restore the first folder backup
if (folderBackups && folderBackups.length > 0) {
console.log('\n=== Test 12: Restore Folder Backup ===');
const timestamp = folderBackups[0].timestamp;
// Modify a file in the folder to verify restoration
fs.writeFileSync(testFileInFolder1, `This file was modified before restore at ${new Date().toISOString()}`);
console.log(`Modified test file before restore: ${testFileInFolder1}`);
const folderRestoreResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_restore',
arguments: {
folder_path: testFolderStructure,
timestamp: timestamp
}
},
id: Date.now().toString()
});
console.log('Folder restore result:', JSON.stringify(folderRestoreResult.result, null, 2));
// Verify the file was restored
const restoredContent = fs.readFileSync(testFileInFolder1, 'utf8');
console.log(`Restored file content: ${restoredContent}`);
} else {
console.log('No folder backups found to restore');
}
// Test 13: Restore with emergency backup creation
if (folderBackups && folderBackups.length > 0) {
console.log('\n=== Test 13: Restore with Emergency Backup ===');
const timestamp = folderBackups[0].timestamp;
// Modify a file in the folder to verify restoration and emergency backup
fs.writeFileSync(testFileInFolder1, `This file was modified before emergency backup restore at ${new Date().toISOString()}`);
console.log(`Modified test file before emergency backup restore: ${testFileInFolder1}`);
const emergencyRestoreResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_folder_restore',
arguments: {
folder_path: testFolderStructure,
timestamp: timestamp,
create_emergency_backup: true
}
},
id: Date.now().toString()
});
console.log('Folder restore with emergency backup result:', JSON.stringify(emergencyRestoreResult.result, null, 2));
}
// Test 14: List all backups including emergency backups
console.log('\n=== Test 14: List All Backups Including Emergency Backups ===');
const listAllResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_list_all',
arguments: { include_emergency: true }
},
id: Date.now().toString()
});
console.log('All backups list:', JSON.stringify(listAllResult.result, null, 2));
// Test 15: Verify emergency backups have metadata
console.log('\n=== Test 15: Verify Emergency Backups Have Metadata ===');
let emergencyBackups = [];
if (listAllResult.result && listAllResult.result.content && listAllResult.result.content.length > 0) {
try {
const allBackups = JSON.parse(listAllResult.result.content[0].text);
emergencyBackups = allBackups.emergency_backups || [];
console.log(`Found ${emergencyBackups.length} emergency backups with metadata`);
// Check if we have emergency backups with metadata
if (emergencyBackups.length > 0) {
console.log('Emergency backups with metadata found:', JSON.stringify(emergencyBackups, null, 2));
} else {
console.log('No emergency backups with metadata found. This may indicate an issue with emergency backup metadata creation.');
}
} catch (err) {
console.error('Error parsing all backups list:', err);
}
}
// Test 16: File restore with emergency backup
console.log('\n=== Test 16: File Restore with Emergency Backup ===');
// Modify test file
fs.writeFileSync(testFile, `This file was modified before emergency backup restore at ${new Date().toISOString()}`);
console.log(`Modified test file before emergency backup restore: ${testFile}`);
// Get the latest backup timestamp
const latestFileBackups = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_list',
arguments: { file_path: testFile }
},
id: Date.now().toString()
});
let fileBackups = [];
if (latestFileBackups.result && latestFileBackups.result.content && latestFileBackups.result.content.length > 0) {
try {
fileBackups = JSON.parse(latestFileBackups.result.content[0].text);
} catch (err) {
console.error('Error parsing file backups list:', err);
}
}
if (fileBackups && fileBackups.length > 0) {
const fileTimestamp = fileBackups[0].timestamp;
const fileEmergencyRestoreResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_restore',
arguments: {
file_path: testFile,
timestamp: fileTimestamp,
create_emergency_backup: true
}
},
id: Date.now().toString()
});
console.log('File restore with emergency backup result:', JSON.stringify(fileEmergencyRestoreResult.result, null, 2));
// List all backups again to verify the new emergency backup
const finalListAllResult = await sendRequest({
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: 'backup_list_all',
arguments: { include_emergency: true }
},
id: Date.now().toString()
});
// Check for new emergency backups
let finalEmergencyBackups = [];
if (finalListAllResult.result && finalListAllResult.result.content && finalListAllResult.result.content.length > 0) {
try {
const finalAllBackups = JSON.parse(finalListAllResult.result.content[0].text);
finalEmergencyBackups = finalAllBackups.emergency_backups || [];
console.log(`Found ${finalEmergencyBackups.length} emergency backups with metadata after file restore`);
// Check if we have more emergency backups than before
if (finalEmergencyBackups.length > emergencyBackups.length) {
console.log('New emergency backup with metadata created successfully!');
} else {
console.log('No new emergency backup metadata found. This may indicate an issue with file emergency backup metadata creation.');
}
} catch (err) {
console.error('Error parsing final all backups list:', err);
}
}
} else {
console.log('No file backups found to restore');
}
console.log('\nAll tests completed successfully!');
} catch (error) {
console.error('Test failed:', error);
} finally {
// Clean up
server.stdin.end();
process.exit(0);
}
}
// Run the tests
runTests();